package be.destin.abdera;

import java.util.HashMap;
import java.util.Map;

import org.apache.abdera.ext.opensearch.server.OpenSearchInfo;
import org.apache.abdera.ext.opensearch.server.OpenSearchUrlAdapter;
import org.apache.abdera.ext.opensearch.server.OpenSearchUrlInfo;
import org.apache.abdera.ext.opensearch.server.OpenSearchUrlParameterInfo;
import org.apache.abdera.protocol.server.CollectionAdapter;
import org.apache.abdera.protocol.server.ProviderHelper;
import org.apache.abdera.protocol.server.RequestContext;
import org.apache.abdera.protocol.server.RequestProcessor;
import org.apache.abdera.protocol.server.ResponseContext;
import org.apache.abdera.protocol.server.WorkspaceManager;
import org.apache.abdera.protocol.server.provider.basic.BasicProvider;
import org.apache.log4j.Logger;

public class MultiCollectionOpenSearchUrlRequestProcessor implements RequestProcessor // CANNOT extends OpenSearchUrlRequestProcessor
{

	/** log4j category */
	private static Logger log = Logger.getLogger(MultiCollectionOpenSearchUrlRequestProcessor.class);

	/*copied from OpenSearchUrlRequestProcessor*/
    private OpenSearchInfo openSearchInfo;

    /*copied from OpenSearchUrlRequestProcessor*/
    public ResponseContext process(final RequestContext requestContext,
                                   final WorkspaceManager workspaceManager,
                                   final CollectionAdapter collectionAdapter) {
        String method = requestContext.getMethod();
        if (method.equalsIgnoreCase("GET")) {
            OpenSearchUrlInfo urlInfo = this.getMatchingUrlInfo(requestContext);
            if (urlInfo != null) {
                OpenSearchUrlAdapter adapter = urlInfo.getOpenSearchUrlAdapter();
                if (adapter != null) {
                    Map<String, String> params = this.getUrlParametersFromRequest(requestContext, urlInfo);
                    params.put("collection", requestContext.getTarget().getParameter(BasicProvider.PARAM_FEED));
                    params.put("entry", requestContext.getTarget().getParameter(BasicProvider.PARAM_ENTRY));
                    params.put("navigation", requestContext.getTarget().getParameter(AbstractCorrectedWorkspaceProvider.PARAM_NAVIGATION));
                    return adapter.search(requestContext, params);
                } else {
                	log.error(urlInfo.getSearchPath()+": no Search adapter?");
                    return ProviderHelper.notfound(requestContext);
                }
            } else {
            	log.error(requestContext.getTargetPath()+": no matching URL?");
                return ProviderHelper.notfound(requestContext);
            }
        } else {
            return null;
        }
    }

    /*copied from OpenSearchUrlRequestProcessor*/
    public void setOpenSearchInfo(OpenSearchInfo openSearchInfo) {
        this.openSearchInfo = openSearchInfo;
    }

    /*MODIFIED from OpenSearchUrlRequestProcessor*/
    private OpenSearchUrlInfo getMatchingUrlInfo(RequestContext request) {
        String targetSearchPath = request.getTargetPath();
        targetSearchPath = this.stripSlashes(targetSearchPath.substring(0, targetSearchPath.indexOf("?")));
        OpenSearchUrlInfo result = null;
        String collectionId = request.getTarget().getParameter(BasicProvider.PARAM_FEED);
        if (collectionId == null) collectionId = "";
        String entryId = request.getTarget().getParameter(BasicProvider.PARAM_ENTRY);
        if (entryId == null) entryId = "";
        String navigationId = request.getTarget().getParameter(AbstractCorrectedWorkspaceProvider.PARAM_NAVIGATION);
        if (navigationId == null) navigationId = "";
        for (OpenSearchUrlInfo urlInfo : this.openSearchInfo.getUrls()) {
            String searchPath = this.stripSlashes(urlInfo.getSearchPath()
            						.replaceAll("\\{"+BasicProvider.PARAM_FEED+"\\}", collectionId)
            						.replaceAll("\\{"+BasicProvider.PARAM_ENTRY+"\\}", entryId)
            						.replaceAll("\\{"+AbstractCorrectedWorkspaceProvider.PARAM_NAVIGATION+"\\}", navigationId));
            if (searchPath.equals(targetSearchPath)) {
                result = urlInfo;
                break;
            } else {
            	log.debug("["+targetSearchPath+"] NOT ["+searchPath+"]");
            }
        }
        return result;
    }

    /*copied from OpenSearchUrlRequestProcessor*/
    private Map<String, String> getUrlParametersFromRequest(RequestContext request, OpenSearchUrlInfo urlInfo) {
        Map<String, String> result = new HashMap<String, String>();
        for (OpenSearchUrlParameterInfo paramInfo : urlInfo.getSearchParameters()) {
            // TODO : enforce mandatory parameters?
            String name = paramInfo.getName();
            String value = request.getParameter(name);
            if (value != null) {
                result.put(name, value);
            }
        }
        return result;
    }

    /*copied from OpenSearchUrlRequestProcessor*/
    private String stripSlashes(String path) {
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        return path;
    }
}
